<!--
 * @Author: anxia.ack anchenkai@come-future.com
 * @Date: 2025-04-14 00:04:49
 * @LastEditors: anxia.ack anchenkai@come-future.com
 * @LastEditTime: 2025-04-21 22:12:57
 * @FilePath: /free-learning/src/views/course-manage/course-chapters/index.vue
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<script setup lang="ts">
import { ref, reactive, onMounted, nextTick, watch } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import CourseChaptersTour from "./tour.vue";
import {
  getCourseChapters,
  addCourseChapters,
  updateCourseChapters,
  deleteCourseChapters,
  getCourseChaptersSort,
  updateCourseChaptersSort,
} from "@/api/course/course-chapters";
import type { CourseChapters, CourseChaptersSortVO } from "@/api/course/course-chapters/type";
import { useRoute } from "vue-router";
import draggable from "vuedraggable";
import FileUpload from "@/components/Upload/FileUpload.vue";
import PromiseUpload, { VIDEO_TYPE } from "@/utils/promise-upload";
import FileAPI from "@/api/file";
import tourConfig from "@/utils/tourConfig";
import { useUploadMessageStore, useUserStore } from "@/store";
import { mockData, mockSortData } from "./mock";
defineOptions({
  name: "CourseChapters",
});

const route = useRoute();
const courseId = ref(Number(route.query.courseId));

// 表格数据
const tableData = ref<CourseChapters[]>([]);
const loading = ref(false);
const total = ref(0);

// 分页参数
const pagination = reactive({
  pageNum: 1,
  pageSize: 10,
});

// 对话框控制
const dialogVisible = ref(false);
const dialogTitle = ref("");
const formData = ref<Partial<CourseChapters>>({
  courseId: courseId.value,
  chapterName: "",
  chapterOrder: 0,
  chapterDes: "",
  chapterUrl: "",
});

// 表单校验规则
const rules = {
  chapterName: [{ required: true, message: "请输入章节标题", trigger: "blur" }],
  chapterOrder: [{ required: true, message: "请输入章节序号", trigger: "blur" }],
  chapterUrl: [{ required: true, message: "请上传视频文件", trigger: "change" }],
};

// 排序相关
const sortDialogVisible = ref(false);
const sortTableData = ref<CourseChaptersSortVO[]>([]);
const sortLoading = ref(false);

// 获取章节列表
const fetchData = async () => {
  loading.value = true;
  try {
    const res = await getCourseChapters({
      courseId: courseId.value,
      pageNum: pagination.pageNum,
      pageSize: pagination.pageSize,
    });
    tableData.value = isMock.value ? mockData : res.records;
    total.value = res.total;
  } catch (error) {
    ElMessage.error("获取章节列表失败");
  } finally {
    loading.value = false;
  }
};

// 处理分页变化
const handlePageChange = (page: number) => {
  pagination.pageNum = page;
  fetchData();
};

// 处理每页条数变化
const handleSizeChange = (size: number) => {
  pagination.pageSize = size;
  pagination.pageNum = 1;
  fetchData();
};

// 打开新增/编辑对话框
const handleDialog = (row?: CourseChapters) => {
  if (row) {
    dialogTitle.value = "编辑章节";
    formData.value = { ...row };
  } else {
    dialogTitle.value = "新增章节";
    formData.value = {
      courseId: courseId.value,
      chapterName: "",
      chapterOrder: tableData.value.length + 1,
      chapterDes: "",
      chapterUrl: "",
    };
  }
  dialogVisible.value = true;
};

const formRef = ref();
// 保存数据
const handleSave = () => {
  if (isMock.value) {
    ElMessage.warning("当前为模拟数据，无法保存");
    return;
  }
  formRef.value?.validate(async (valid: boolean) => {
    if (valid) {
      try {
        formData.value.chapterUrl = "uploading";
        if (formData.value.id) {
          await updateCourseChapters(formData.value as CourseChapters);
          ElMessage.success("更新成功");
        } else {
          const res = await addCourseChapters(formData.value as CourseChapters);
          formData.value = { ...res };
          ElMessage.success("新增成功");
        }
        if (file.value) {
          promiseUpload?.add(file.value, formData.value as CourseChapters);
        }
        handleCancel();
        fetchData();
      } catch (error) {
        ElMessage.error("操作失败");
      }
    }
  });
};
const uploadMessageStore = useUploadMessageStore();
watch(
  () => uploadMessageStore.uploadMessage,
  (newVal) => {
    fetchData();
  }
);
const handleCancel = () => {
  dialogVisible.value = false;
  file.value = undefined;
  formData.value.chapterUrl = "";
  formRef.value?.resetFields();
  if (fileRef.value) {
    fileRef.value.value = "";
  }
};

// 删除数据
const handleDelete = async (row: CourseChapters) => {
  if (isMock.value) {
    ElMessage.warning("当前为模拟数据，无法删除");
    return;
  }
  try {
    await ElMessageBox.confirm("确认删除该章节吗？", "提示", {
      type: "warning",
    });
    await deleteCourseChapters(row.id);
    ElMessage.success("删除成功");
    fetchData();
  } catch (error) {
    if (error !== "cancel") {
      ElMessage.error("删除失败");
    }
  }
};

// 打开排序对话框
const handleSort = async () => {
  sortDialogVisible.value = true;
  sortLoading.value = true;
  try {
    const res = await getCourseChaptersSort(courseId.value);
    sortTableData.value = isMock.value ? mockSortData : res;
  } catch (error) {
    ElMessage.error("获取排序数据失败");
  } finally {
    sortLoading.value = false;
  }
};

// 处理拖拽排序
const handleSortChange = async () => {
  if (isMock.value) {
    ElMessage.warning("排序成功（mock）");
    return;
  }
  try {
    // 更新序号
    const sortData = sortTableData.value.map((item, index) => ({
      id: item.id,
      chapterName: item.chapterName,
      chapterOrder: index + 1,
    }));
    await updateCourseChaptersSort(sortData);
    const res = await getCourseChaptersSort(courseId.value);
    sortTableData.value = res;
    ElMessage.success("排序更新成功");
  } catch (error) {
    ElMessage.error("排序更新失败");
    // 恢复原始顺序
    const res = await getCourseChaptersSort(courseId.value);
    sortTableData.value = res;
  }
};

const handleSortClose = () => {
  sortTableData.value = [];
  dialogVisible.value = false;
  fetchData();
};
let promiseUpload: PromiseUpload | undefined = inject("PromiseUpload");
if (!promiseUpload) {
  promiseUpload = new PromiseUpload();
  provide("PromiseUpload", promiseUpload);
}
const file = ref<File | undefined>();
const fileRef = ref<HTMLInputElement | null>(null);
const videoDialogVisible = ref(false);
const videoUrl = ref("");
const handleWatchVideo = (row: CourseChapters) => {
  videoDialogVisible.value = true;
  videoUrl.value = row.chapterUrl;
};
const handleFileChange = (e: Event) => {
  const uploadFile = (e.target as HTMLInputElement).files?.[0];
  if ((uploadFile?.size || 0) > 1024 * 1024 * 500) {
    ElMessage.error("文件大小不能超过500MB");
    return;
  }

  if (!VIDEO_TYPE.includes(uploadFile?.type || "")) {
    ElMessage.error("文件类型不支持");
    return;
  }
  formData.value.fileName = uploadFile?.name || "";
  formData.value.chapterUrl = "waitUploading";
  file.value = uploadFile;
  // if (file) {
  //   const promiseUpload = new PromiseUpload();
  //   promiseUpload.add(file, formData.value as CourseChapters);
  // }
};
const handleDeleteFile = () => {
  if (isMock.value) {
    ElMessage.warning("当前为模拟数据，无法删除");
    return;
  }
  formData.value.chapterUrl = "";
  formData.value.fileName = "";
};
const isMock = ref(false);
const userStore = useUserStore();
onMounted(() => {
  const isFirstInCourseChapters = tourConfig.getTourConfig("isFirstInCourseChapters");
  isMock.value =
    (isFirstInCourseChapters === undefined ? true : isFirstInCourseChapters) &&
    userStore.userInfo.perms.includes("sys:course:pass");
  fetchData();
});
const handleTourFinish = () => {
  isMock.value = false;
  fetchData();
};
</script>

<template>
  <div class="app-container">
    <el-card>
      <template #header>
        <div class="card-header">
          <span>课程章节管理</span>
          <div>
            <el-button id="courseChapterSort-tour" type="primary" @click="handleSort">
              章节排序
            </el-button>
            <el-button
              id="courseChapterAdd-tour"
              v-hasPerm="['sys:course:pass']"
              type="primary"
              @click="handleDialog()"
            >
              新增章节
            </el-button>
          </div>
        </div>
      </template>

      <!-- 表格 -->
      <el-table v-loading="loading" :data="tableData" border style="width: 100%">
        <el-table-column type="index" width="50" align="center" />
        <el-table-column
          prop="chapterName"
          label="章节标题"
          min-width="180"
          show-overflow-tooltip
        />
        <el-table-column prop="chapterDes" label="章节描述" min-width="200" show-overflow-tooltip />
        <el-table-column v-permission="['sys:course:pass']" label="操作" width="180" fixed="right">
          <template #default="{ row }">
            <el-button
              id="courseChapterWatchVideo-tour"
              type="primary"
              link
              @click="handleWatchVideo(row)"
            >
              查看视频
            </el-button>
            <el-button id="courseChapterEdit-tour" type="primary" link @click="handleDialog(row)">
              编辑
            </el-button>
            <el-button id="courseChapterDelete-tour" type="danger" link @click="handleDelete(row)">
              删除
            </el-button>
          </template>
        </el-table-column>
      </el-table>
      <CourseChaptersTour @finish="handleTourFinish" />
      <!-- 分页 -->
      <div class="pagination-container">
        <el-pagination
          v-model:current-page="pagination.pageNum"
          v-model:page-size="pagination.pageSize"
          :page-sizes="[10, 20, 50, 100]"
          :total="total"
          layout="total, sizes, prev, pager, next, jumper"
          @size-change="handleSizeChange"
          @current-change="handlePageChange"
        />
      </div>
    </el-card>

    <el-dialog v-model="videoDialogVisible" title="查看视频" width="700px">
      <video v-if="videoUrl.includes('http')" :src="videoUrl" controls class="w-full h-full" />
      <div v-else>
        <p>视频上传中...</p>
      </div>
    </el-dialog>
    <!-- 新增/编辑对话框 -->
    <el-dialog v-model="dialogVisible" :title="dialogTitle" width="600px">
      <el-form ref="formRef" :rules="rules" :model="formData" label-width="100px">
        <el-form-item label="章节标题" prop="chapterName">
          <el-input v-model="formData.chapterName" placeholder="请输入章节标题" />
        </el-form-item>
        <el-form-item label="章节序号" prop="chapterOrder">
          <el-input-number v-model="formData.chapterOrder" :min="1" :max="999" />
        </el-form-item>
        <el-form-item label="章节描述" prop="chapterDes">
          <el-input
            v-model="formData.chapterDes"
            type="textarea"
            :rows="4"
            placeholder="请输入章节描述"
          />
        </el-form-item>
        <el-form-item label="视频文件" prop="chapterUrl">
          <div v-if="formData.chapterUrl !== 'uploading'">
            <input
              ref="fileRef"
              type="file"
              accept="video/*"
              :disabled="formData.chapterUrl?.startsWith('http')"
              @change="handleFileChange"
            />
            <p class="uploading-text">点击确认后，文件将开始上传，请勿重复上传</p>
          </div>
          <div>
            <div v-if="formData.chapterUrl === 'uploading'">文件上传中...</div>
            <div
              v-else-if="formData.chapterUrl?.startsWith('http')"
              class="flex items-center justify-between"
            >
              <p
                class="mr-20 cursor-pointer"
                @click="
                  () => {
                    FileAPI.downloadFile(formData.chapterUrl as string, formData.fileName);
                  }
                "
              >
                {{ formData.fileName }}
              </p>
              <el-icon class="cursor-pointer" @click="handleDeleteFile"><Delete /></el-icon>
            </div>
          </div>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="handleCancel">取消</el-button>
          <el-button type="primary" @click="handleSave">确定</el-button>
        </span>
      </template>
    </el-dialog>

    <!-- 排序对话框 -->
    <el-dialog v-model="sortDialogVisible" title="章节排序" width="800px" @close="handleSortClose">
      <div class="sort-table">
        <draggable
          v-model="sortTableData"
          item-key="id"
          handle=".drag-handle"
          :animation="150"
          @end="handleSortChange"
        >
          <template #item="{ element }">
            <div class="sort-item">
              <el-icon class="drag-handle"><Rank /></el-icon>
              <span class="sort-order">{{ element.chapterOrder }}</span>
              <span class="sort-title">{{ element.chapterName }}</span>
            </div>
          </template>
        </draggable>
      </div>
    </el-dialog>
  </div>
</template>

<style lang="scss" scoped>
.app-container {
  padding: 20px;

  .card-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }

  .pagination-container {
    margin-top: 20px;
    display: flex;
    justify-content: flex-end;
  }

  .drag-handle {
    cursor: move;
    color: #909399;
  }

  .sort-table {
    .sort-item {
      display: flex;
      align-items: center;
      padding: 12px;
      background: #fff;
      border: 1px solid #ebeef5;
      margin-bottom: 8px;
      cursor: move;

      &:hover {
        background: #f5f7fa;
      }

      .drag-handle {
        color: #909399;
        margin-right: 12px;
        cursor: move;
      }

      .sort-order {
        width: 60px;
        text-align: center;
        color: #606266;
      }

      .sort-title {
        flex: 1;
        color: #303133;
      }
    }
  }
  .uploading-text {
    color: #909399;
  }
}
</style>
